import threading, pathlib, cv2, queue
from datetime import datetime
from typing import Any
from src.driver.base import ICamera
from src.data.structures import BinocularImagePair


class Pipeline:
    """相机管道"""

    def __init__(self, camera: ICamera, output_dir: pathlib.Path, max_cache: int = 10):
        self._camera = camera
        self._output_dir = output_dir
        self._save_queue = queue.Queue(maxsize=max_cache)
        self._save_thread = threading.Thread(target=self._saveLoop, daemon=True)
        self._max_cache = max_cache

    def start(self):
        self._camera.open()
        self._save_thread.start()

    def stop(self):
        self._camera.close()
        self._save_queue.put(None)  #  poison pill
        self._save_thread.join()

    def saveOnce(self, pair: BinocularImagePair, idx: int = 0) -> bool:
        """非阻塞入队当前帧

        返回 True 表示成功入队: False 表示队列满且已丢弃最旧请求
        """
        # 队列满 → 丢弃最旧, 保证最新总能入队
        while self._save_queue.full():
            try:
                self._save_queue.get_nowait()
            except queue.Empty:
                break

        # 非阻塞入队最新请求
        try:
            self._save_queue.put_nowait((pair, idx))
            return True
        except queue.Full:
            return False

    def _saveLoop(self):
        """后台落盘"""
        while True:
            item = self._save_queue.get()  # 阻塞直到有请求
            if item is None:  # poison pill
                break
            pair, idx = item
            if self._output_dir and not self._output_dir.exists():
                self._output_dir.mkdir(parents=True, exist_ok=True)
            stem = self._output_dir / datetime.now().strftime("%Y%m%d_%H%M%S_%f")
            cv2.imwrite(str(stem) + f"_left_{idx}.png", pair.left_image)
            cv2.imwrite(str(stem) + f"_right_{idx}.png", pair.right_image)
